/**
 * 以puppter的方式直接解析并运行json
 * @author mumulin
 * @email 1058386570@qq.com
 * @date 2025/10
 */
import fs from 'fs';
// 跳过当前步骤
export const jump = 'jump'
// 原生点击
export const action_click = "click"
// 延迟
export const action_delay = "delay"
// 跳转指定下标的步骤
export const action_jumpIndex = "jumpIndex"
// 重新当前json文件步骤
export const action_reStep = "reStep"
// 当前步骤运行条件
export const action_replayCheck = "replayCheck"
// page click事件
export const action_pageClick = "pageClick"
// 置换步骤属性
export const action_replace = "replace"
// 文件上传
export const action_fileUpload = "fileUpload"

export const Trusteeship = {
	// 事件改为原生点击
	async nativeClick({ data, step, index, page }, {target,skip = true}){
	    if (step.type === 'click' && step.selectors?.[0]?.[0] === target) {
			try{
				await page.waitForSelector(target,{
					timeout: step.timeout
				})
				await page.evaluate((target) => {
					document.querySelector(target).click();
				},target);
				console.log('介入 click',target,'成功');
			}catch(e){
				console.log('介入 click',target,'失败',e);
			}
			if(skip) return {action:jump}
		}
	},
	// 设置一个page点击
	async pageClick({ data, step, index, page }, {pageClick, target, type,skip,timeout=20000}){
		if (step.type === type && step.selectors?.[0]?.[0] === target) {
			try{
				await page.waitForSelector(pageClick,{
					timeout
				})
				await page.click(pageClick);
				console.log('pageClick',pageClick,'成功');
			}catch(e){
				console.log('pageClick',pageClick,'失败：节点不存在');
			}
			if(skip) return {action:jump}
		}
	},
	// 当前步骤延迟执行
	async waitNext({ data, step, index, page }, { delay = 5000, target, type}){
		if (step.type === type && step.selectors?.[0]?.[0] === target) {
			await base.delay(delay);
			// await page.waitForTimeout(1000); // 等待1秒
		}
	},
	//replayCheck 返回bool值 当前步骤是否需要执行
	async replayCheck({ data, step, index, page },{target,type,replayCheck}){
		if (step.type === type && step.selectors?.[0]?.[0] === target) {
			if(!replayCheck) return
			let rs = await replayCheck({data, step, index, page})
			console.log('是否存在要执行',rs)
			return rs ? null: {action:jump}
		}
	},
	// 将replace中的属性替换到当前步骤中
	async replaceAttr({ data, step, index, page },{target,type, replace}){
		if (step.type === type && step.selectors?.[0]?.[0] === target) {
			if(!replace) return
			for (const key in replace) {
				const val =replace[key]
				step[key] = typeof val == 'function' ? (await val({data, step, index, page})) : val
			}
		}
	},
	// 文件上传
	async uploadFile({ data, step, index, page },{target,type, files}){
		if (step.type === type && step.selectors?.[0]?.[0] === target) {
			try {
				console.log('当前 CdpFrame 的 URL：', page.url()); // 关键：打印 iframe 实例的 URL
				// console.log('主框架的 URL：', page.mainFrame().url()); // 对比主框架 URL
				// console.log('page:',page,target)
				await page.evaluate((target) => {
					const el = document.querySelector(target);
					console.log(el,target,document)
				},target)

				const fileInput = await page.waitForSelector(target,{ timeout: step.timeout });
				if (!fileInput) {
					throw new Error('未找到文件输入元素（input[type="file"]）');
				}
				const filePath = typeof files == 'string' ? [files] : files
				// 检查所有文件是否存在
				filePath.forEach(path => {
					if (!fs.existsSync(path)) {
						throw new Error(`文件不存在：${path}`);
					}
				});
				console.log(`上传文件：${filePath.join(', ')}`, target);
				await fileInput.uploadFile(...filePath);
			} catch (err) {
				console.error('文件上传失败：', err.message, target);
			}
			return { action: jump }
		}
	},
}

const base =  {
	// 命令行参数处理器
	CommandParm(){
		// 默认参数
		const defaultParams = {
			runType:'puppter',
			file:null,//执行文件
			fload:null,//执行文件夹  二选一
			steps:null,//执行步骤(文件夹必须)
		}
		// 命令参数
		const cmdParms = {}
		// 遍历所有参数
		process.argv.forEach((val, index) => {
			// console.log(`${index}: ${val}`);
			if(index>1 && val){
				const key = val.split('=')[0]
				const value = val.split('=')[1]
				cmdParms[key.trim()] = value ? value.trim() : value
			}
		});
		for (const key in defaultParams) {
		    if(defaultParams[key] !== null && cmdParms[key] === undefined) cmdParms[key] = defaultParams[key]
		}
		return cmdParms
	},
	// 选择器统一格式
	parseSelectors(arr){
		return arr.map(item=>(typeof item == 'string') ? [item] : item)
	},
	// 延时
	delay(times){
		return new Promise((resolve, reject) => setTimeout(resolve,times))
	},
	// 检查指定dom是否存在
	async checkHasDom(page, target){
		try{
			await page.waitForSelector(target,{
				timeout: 10000,
				visible: true
			})
			return true
		}catch(e){
			return false
		}
	},
	// 获取当前执行上下文 根据setp.frame判断是否切换iframe
	getContext(step,page){
	    if (step.frame && step.frame.length > 0) {
			const frameIndex = step.frame[0];
			const allFrames = page.frames(); // 获取所有 iframe（包括主页面） 第0个是主框架page.mainFrame()
			// console.log('框架：',allFrames)
			if (frameIndex >= 0 && frameIndex < allFrames.length) {
				const targetFrame = allFrames[frameIndex+1];
				console.log(`切换到 iframe[${frameIndex}]，url: ${targetFrame.url()}`);
				return targetFrame
			} else {
				console.warn(`⚠️ iframe 索引${frameIndex}无效，当前存在${allFrames.length}个iframe`);
			}
		}
	},
	// 计算所需执行次数 （数组点语法取对应字段的长度） field不存在按正常运行1次
	getfieldForRunTimes(data, field){
		if(!field) return 1
		let count = 0;
		let targetField = data
		const toField = field.split('.').map(item=>item.trim())
		const getFieldChild = (data,field) => data == undefined ? null : data[field]
		toField.forEach(item=>{
			if(targetField) targetField = getFieldChild(targetField,item)
		})
		count = targetField?.length||0
		return count
	},
	// 事件接入
	eventTrusteeship({ data, step, index, page},param){
		if(!param) return console.error("事件参数错误")
		switch(param.runType){
			case action_click: return Trusteeship.nativeClick({ data, step, index, page}, param)
			case action_delay: return Trusteeship.waitNext({ data, step, index, page}, param)
			case action_jumpIndex : return (index === param.jumpIndex) ? {action:jump} : null
			case action_replayCheck : return Trusteeship.replayCheck({ data, step, index, page}, param)
			case action_pageClick : return Trusteeship.pageClick({ data, step, index, page}, param)
			case action_replace : return Trusteeship.replaceAttr({ data, step, index, page}, param)
			case action_fileUpload : return Trusteeship.uploadFile({ data, step, index, page}, param)
		}
	},
	// 全部事件接入 推荐
	async eventTrusteeshipAll({ data, step, index, page, option=[]}){
	    for (let i = 0; i < option.length; i++) {
			const item = option[i];
			let rs = await this.eventTrusteeship({
				data, step, index, page
			},item)
			if(rs) return rs
		}
	}
}
export default base